home *** CD-ROM | disk | FTP | other *** search
/ PC Graphics Unleashed / PC Graphics Unleashed.iso / ch21 / ffd3d.c < prev    next >
C/C++ Source or Header  |  1994-07-30  |  13KB  |  612 lines

  1. #include <conio.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <graphics.h>
  5. #include <math.h>
  6. #include <alloc.h>
  7.  
  8. #define TOL 0.0005
  9. #define PI  3.14159265358979323846
  10. #define X_AXIS 1
  11. #define Y_AXIS 2
  12. #define Z_AXIS 3
  13.  
  14.  
  15. typedef struct {
  16.  float far x,y,z;
  17. } POINT3D;
  18.  
  19. typedef struct {
  20.  int x,y;
  21. } POINTint;
  22.  
  23.  
  24. /* World Limits in 2D */
  25. float WXleft;
  26. float WXright;
  27. float WYtop;
  28. float WYbottom;
  29.  
  30. /* Device Limits */
  31. int DXmin;
  32. int DYmin;
  33. int DYmax;
  34. int DXmax;
  35.  
  36. /* Rotations for 3D View in Radians*/
  37. float RX;
  38. float RY;
  39. float RZ;
  40. float COSRX;
  41. float SINRX;
  42. float COSRY;
  43. float SINRY;
  44. float COSRZ;
  45. float SINRZ;
  46.  
  47.  
  48.  
  49. void InitGraphics(void);
  50. float DegToRad(float deg);
  51. float RadToDeg(float rad);
  52. POINT3D World3DToWorld2D(POINT3D p);
  53. POINTint World2DToDevice(POINT3D p);
  54. void drawpoint(POINT3D p1);
  55. void drawline(POINT3D p1,POINT3D p2);
  56. void drawaxis(void);
  57. void SetAxesAngles(float rx, float ry, float rz);
  58. void LoadAFile(char *str);
  59. void SaveAFile(char *str);
  60. float Coordinate(int i);
  61. void InitBezierCube(void);
  62. void GetMaxima(float *xi,float *xf,
  63.            float *yi,float *yf,
  64.            float *zi,float *zf);
  65. void ScaleBezierCube(float x, float y, float z);
  66. void DrawBezierCube(void);
  67. void FreezeBezierCube(float x,float y,float z);
  68. float UVW(float vmin, float vmax, float value);
  69. float Bernstein(float t, int i);
  70. POINT3D GetBezierPoint(float u, float v, float w);
  71. void RotatePatch(int patch, int axis, float deg);
  72. void TranslatePatch(int patch, int axis, float d);
  73. void ScalePatch(int patch, int axis, float s);
  74. void GoFFD(void);
  75. void drawObjects(int n);
  76. void SetView(void);
  77.  
  78. POINT3D Cube[4][4][4];
  79. POINT3D far *Object;
  80. POINT3D far *Object2;
  81. #define MAXFACES 600      // object may have up to 2000 faces
  82.               // COMPILE USING LARGE MEMORY MODEL
  83. int PointNum;
  84. float XS,YS,ZS;
  85.  
  86.  
  87. void main()
  88. {
  89.   POINT3D p;
  90.   int i, loop;
  91.   float xmin, xmax,
  92.     ymin, ymax,
  93.     zmin, zmax;
  94.  
  95.   if((Object = (POINT3D *)farcalloc(3*MAXFACES, sizeof(POINT3D))) == NULL) {
  96.       closegraph();
  97.       printf("ERROR: Can't allocate database!\n");
  98.       exit(1);
  99.   }
  100.  
  101.   if((Object2 = (POINT3D *)farcalloc(3*MAXFACES, sizeof(POINT3D))) == NULL) {
  102.       closegraph();
  103.       printf("ERROR: Can't allocate database!\n");
  104.       exit(1);
  105.   }
  106.  
  107.   LoadAFile("bottle.raw");
  108.   //LoadAFile("plate.raw");
  109.  
  110.   InitGraphics();
  111.   setbkcolor(WHITE);
  112.   setcolor(BROWN);
  113.   cleardevice();
  114.   /* World Limits */
  115.   WXleft   = -1.4;
  116.   WXright  =  1.4;
  117.   WYtop    =  1.4;
  118.   WYbottom = -1.4;
  119.  
  120.   InitBezierCube();
  121.   GetMaxima(&xmin,&xmax,&ymin,&ymax,&zmin,&zmax);
  122.   ScaleBezierCube(xmax, ymax, zmax);
  123.   FreezeBezierCube(xmax,ymax,zmax);
  124.  
  125.   SetView();
  126.   drawObjects(1);
  127.   DrawBezierCube();
  128.  
  129.   for(loop=0;loop<10;loop++) {
  130.  
  131.    InitBezierCube();
  132.    ScaleBezierCube(xmax, ymax, zmax);
  133.  
  134.    // ANIMATION COMMANDS
  135.  
  136.    //USE WITH BOTTLE.RAW
  137.    RotatePatch(3, Z_AXIS, loop*5.0);
  138.    TranslatePatch(3, Y_AXIS, 0.5);
  139.    TranslatePatch(3, X_AXIS,-0.1*loop);
  140.  
  141.    RotatePatch(0, Z_AXIS, -loop*5.0);
  142.    TranslatePatch(0, Y_AXIS, -0.5);
  143.    TranslatePatch(0, X_AXIS, -0.1*loop);
  144.  
  145.    /*
  146.    // USE WITH PLATE.RAW
  147.    RotatePatch(3, Y_AXIS, loop*9.0);
  148.    RotatePatch(2, Y_AXIS, loop*4.5);
  149.    RotatePatch(1, Y_AXIS, loop*2.0);
  150.    */
  151.    // END OF ANIMATION COMMANDS
  152.  
  153.    GoFFD();
  154.    clearviewport();
  155.    drawaxis();
  156.    drawObjects(2);
  157.    DrawBezierCube();
  158.   }
  159.   printf("\7");
  160.   getch();
  161.   closegraph();
  162. }
  163.  
  164. /* /////////////////////////////////////////////////////// */
  165. void SetView(void) {
  166.     int d;
  167.  
  168.     DXmin = 0.0;
  169.     DYmin = 0.0;
  170.     DYmax = getmaxy();
  171.     DXmax = getmaxy();
  172.     d = (getmaxx() - getmaxy())/2;
  173.     setviewport(d,0,getmaxy()+d,getmaxy(),1);
  174.     SetAxesAngles(20, -15, -5);
  175.     drawaxis();
  176. }
  177.  
  178.  
  179.  
  180. void drawObjects(int n) {
  181.   int i;
  182.  
  183.   setcolor(BROWN);
  184.   if (n==1)
  185.     for(i=0;i<PointNum;i+=3) {
  186.       drawline(Object[i],Object[i+1]);
  187.       drawline(Object[i+1],Object[i+2]);
  188.       drawline(Object[i+2],Object[i]);
  189.     }
  190.   else
  191.     for(i=0;i<PointNum;i+=3) {
  192.       drawline(Object2[i],Object2[i+1]);
  193.       drawline(Object2[i+1],Object2[i+2]);
  194.       drawline(Object2[i+2],Object2[i]);
  195.     }
  196. }
  197.  
  198.  
  199. void GoFFD(void) {
  200.   int i;
  201.   float Xuvw, Yuvw, Zuvw;
  202.   for(i=0;i<PointNum;i++) {
  203.     Xuvw = UVW(-XS, XS, Object[i].x);
  204.     Yuvw = UVW(-YS, YS, Object[i].y);
  205.     Zuvw = UVW(-ZS, ZS, Object[i].z);
  206.     Object2[i] = GetBezierPoint(Xuvw, Yuvw, Zuvw);
  207.   }
  208. }
  209.  
  210. void ScalePatch(int patch, int axis, float s){
  211.  int i,k;
  212.  
  213.   for(k=0;k<4;k++)
  214.    for(i=0;i<4;i++)
  215.      switch(axis) {
  216.       case X_AXIS: Cube[i][patch][k].x *= s; break;
  217.       case Y_AXIS: Cube[i][patch][k].y *= s; break;
  218.       case Z_AXIS: Cube[i][patch][k].z *= s; break;
  219.      }
  220.  
  221. }
  222.  
  223.  
  224.  
  225. void TranslatePatch(int patch, int axis, float d){
  226.  int i,k;
  227.  
  228.   for(k=0;k<4;k++)
  229.    for(i=0;i<4;i++)
  230.      switch(axis) {
  231.       case X_AXIS: Cube[i][patch][k].x += d; break;
  232.       case Y_AXIS: Cube[i][patch][k].y += d; break;
  233.       case Z_AXIS: Cube[i][patch][k].z += d; break;
  234.      }
  235.  
  236. }
  237.  
  238. void RotatePatch(int patch, int axis, float deg) {
  239.   float xc=0.0, yc=0.0, zc=0.0;
  240.   float COS, SIN;
  241.   int i,j,k;
  242.   POINT3D p, ptemp;
  243.  
  244.   deg = DegToRad(deg);
  245.   COS = cos(deg);
  246.   SIN = sin(deg);
  247.  
  248.   //find centroid of patch
  249.   for(k=0;k<4;k++)
  250.    for(i=0;i<4;i++) {
  251.       xc += Cube[i][patch][k].x;
  252.       yc += Cube[i][patch][k].y;
  253.       zc += Cube[i][patch][k].z;
  254.    }
  255.  
  256.   //divide by 16 to get center (average)
  257.    xc /= 16.0;
  258.    yc /= 16.0;
  259.    zc /= 16.0;
  260.  
  261.   // translate center of patch to origin
  262.   for(k=0;k<4;k++)
  263.    for(i=0;i<4;i++) {
  264.       Cube[i][patch][k].x -= xc;
  265.       Cube[i][patch][k].y -= yc;
  266.       Cube[i][patch][k].z -= zc;
  267.    }
  268.  
  269.   // now that center of patch is at origin, rotate about axis
  270.   for(k=0;k<4;k++)
  271.     for(i=0;i<4;i++) {
  272.       p = Cube[i][patch][k];
  273.       switch(axis) {
  274.      case X_AXIS:
  275.              ptemp.x  = p.x;
  276.              ptemp.y  = COS*p.y - SIN*p.z;
  277.              ptemp.z  = SIN*p.y + COS*p.z;
  278.              Cube[i][patch][k] = ptemp;
  279.              break;
  280.      case Y_AXIS:
  281.              ptemp.x  = COS*p.x + SIN*p.z;
  282.              ptemp.y  = p.y;
  283.              ptemp.z  = -SIN*p.x + COS*p.z;
  284.              Cube[i][patch][k] = ptemp;
  285.              break;
  286.      case Z_AXIS:
  287.              ptemp.x  = COS*p.x - SIN*p.y;
  288.              ptemp.y  = SIN*p.x + COS*p.y;
  289.              ptemp.z  = p.z;
  290.              Cube[i][patch][k] = ptemp;
  291.              break;
  292.       }
  293.     }
  294.   // translate center of patch back to original place
  295.   for(k=0;k<4;k++)
  296.    for(i=0;i<4;i++) {
  297.       Cube[i][patch][k].x += xc;
  298.       Cube[i][patch][k].y += yc;
  299.       Cube[i][patch][k].z += zc;
  300.    }
  301.  
  302. }
  303.  
  304.  
  305. float UVW(float vmin, float vmax, float value) {
  306.   return( (value - vmin)/(vmax - vmin)  );
  307. }
  308.  
  309. float Bernstein(float t, int i) {
  310.   float v;
  311.   switch(i) {
  312.     case 0: v =  pow((1.0 - t),3); break;
  313.     case 1: v =  3 * t * pow((1.0 - t),2); break;
  314.     case 2: v = 3 * pow(t,2) * (1.0 - t); break;
  315.     case 3: v = pow(t,3); break;
  316.   }
  317.   return(v);
  318. }
  319.  
  320. POINT3D GetBezierPoint(float u, float v, float w) {
  321.  int i,j,k;
  322.  POINT3D q;
  323.  float factor, wk, vk, wkvk;
  324.  
  325.  q.x = q.y = q.z = 0.0;
  326.  for(k=0;k<4;k++) {
  327.   wk = Bernstein(w,k);
  328.   for(j=0;j<4;j++) {
  329.     vk = Bernstein(v,j);
  330.     wkvk = wk * vk;
  331.     for(i=0;i<4;i++) {
  332.       factor = Bernstein(u,i) * wkvk;
  333.       q.x += Cube[i][j][k].x * factor;
  334.       q.y += Cube[i][j][k].y * factor;
  335.       q.z += Cube[i][j][k].z * factor;
  336.     }
  337.   }
  338.  }
  339.  return(q);
  340. }
  341.  
  342. void FreezeBezierCube(float x,float y,float z) {
  343.  
  344.   XS = x;
  345.   YS = y;
  346.   ZS = z;
  347. }
  348.  
  349. void GetMaxima(float *xi,float *xf,
  350.            float *yi,float *yf,
  351.            float *zi,float *zf) {
  352.   int i;
  353.   float x1=1e6,x2=-1e6,
  354.     y1=1e6,y2=-1e6,
  355.     z1=1e6,z2=-1e6;
  356.  
  357.   for(i=0;i<PointNum;i++) {
  358.  
  359.      if(Object[i].x < x1)
  360.     x1 = Object[i].x;
  361.      else
  362.     if(Object[i].x > x2)
  363.        x2 = Object[i].x;
  364.  
  365.      if(Object[i].y < y1)
  366.     y1 = Object[i].y;
  367.      else
  368.     if(Object[i].y > y2)
  369.        y2 = Object[i].y;
  370.  
  371.      if(Object[i].z < z1)
  372.     z1 = Object[i].z;
  373.      else
  374.     if(Object[i].z > z2)
  375.        z2 = Object[i].z;
  376.   }
  377.   *xi = x1;
  378.   *xf = x2;
  379.   *yi = y1;
  380.   *yf = y2;
  381.   *zi = z1;
  382.   *zf = z2;
  383. }
  384.  
  385. float Coordinate(int i) {
  386.   switch(i) {
  387.     case 0: return(-1.0);
  388.     case 1: return(-0.3);
  389.     case 2: return( 0.3);
  390.     default: return( 1.0);  //case 3
  391.   }
  392. }
  393.  
  394. void InitBezierCube(void) {
  395.  int i,j, k;
  396.  
  397.  for(k=0;k<4;k++)
  398.    for(j=0;j<4;j++)
  399.      for(i=0;i<4;i++) {
  400.        Cube[i][j][k].x = Coordinate(i);
  401.        Cube[i][j][k].y = Coordinate(j);
  402.        Cube[i][j][k].z = Coordinate(k);
  403.      }
  404. }
  405.  
  406. void ScaleBezierCube(float x, float y, float z) {
  407.  int i,j, k;
  408.  
  409.  for(k=0;k<4;k++)
  410.    for(j=0;j<4;j++)
  411.      for(i=0;i<4;i++) {
  412.        Cube[i][j][k].x *= x;
  413.        Cube[i][j][k].y *= y;
  414.        Cube[i][j][k].z *= z;
  415.      }
  416. }
  417.  
  418. void DrawBezierCube(void) {
  419.  int i,j, k;
  420.  
  421.  
  422.  setlinestyle(DOTTED_LINE,1, 1);
  423.  setcolor(RED);
  424.  
  425.  for(k=0;k<4;k++)
  426.   for(j=0;j<4;j++)
  427.     for(i=0;i<4;i++)
  428.        drawpoint(Cube[i][j][k]);
  429.  
  430.   for(j=0;j<4;j++)
  431.    for(k=0;k<4;k++)
  432.      for(i=0;i<3;i++)
  433.        drawline(Cube[i][j][k],Cube[i+1][j][k]);
  434.  
  435.   for(j=0;j<4;j++)
  436.    for(i=0;i<4;i++)
  437.      for(k=0;k<3;k++)
  438.        drawline(Cube[i][j][k],Cube[i][j][k+1]);
  439.  
  440.   for(k=0;k<4;k++)
  441.    for(i=0;i<4;i++)
  442.      for(j=0;j<3;j++)
  443.        drawline(Cube[i][j][k],Cube[i][j+1][k]);
  444.  setlinestyle(SOLID_LINE,1, 1);
  445. }
  446.  
  447. void SaveAFile(char *str)
  448. {
  449.  FILE *fptr;
  450.  int i;
  451.  if ((fptr = fopen(str,"w+t")) == NULL)
  452.     printf("\7");
  453.  else {
  454.     for(i=0;i<PointNum;i+=3)
  455.        fprintf(fptr,"%g %g %g %g %g %g %g %g %g\n",
  456.             Object2[i].x,   Object2[i].y,   Object2[i].z,
  457.             Object2[i+1].x, Object2[i+1].y, Object2[i+1].z,
  458.             Object2[i+2].x, Object2[i+2].y, Object2[i+2].z);
  459.     fclose(fptr);
  460.  }
  461. }
  462.  
  463.  
  464. void LoadAFile(char *str)
  465. {
  466.  FILE *fptr;
  467.  float x,y,z;
  468.  int bnum;
  469.  if (  (fptr = fopen(str,"r")) == NULL) {
  470.          printf("\7");
  471.  }
  472.  else {
  473.      bnum = -1;
  474.      while (!feof(fptr)) {
  475.      if ((fscanf(fptr,"%f",&x) > 0) &&
  476.          (fscanf(fptr,"%f",&y) > 0) &&
  477.          (fscanf(fptr,"%f",&z) > 0)) {
  478.           bnum++;
  479.           if(bnum < MAXFACES*3) {
  480.             Object[bnum].x = x;
  481.             Object[bnum].y = y;
  482.             Object[bnum].z = z;
  483.           }
  484.      }
  485.      }
  486.      fclose(fptr);
  487.      PointNum = bnum+1;
  488.  }
  489. }
  490.  
  491.  
  492.  
  493. void InitGraphics(void)
  494. {
  495.  int gdriver = DETECT, gmode, errorcode;
  496.  initgraph(&gdriver, &gmode, "");
  497.  if (gdriver != VGA) {
  498.   printf("VGA graphics card required.\n");
  499.   exit(1);
  500.  }
  501.  errorcode = graphresult();
  502.  if (errorcode != grOk)  /* an error occurred */
  503.  {
  504.    printf("Graphics error: %s\n", grapherrormsg(errorcode));
  505.    printf("Press any key to halt:");
  506.    getch();
  507.    exit(1); /* terminate with an error code */
  508.  }
  509.  setviewport(0,0,getmaxx(),getmaxy(),1);
  510. }
  511.  
  512. float DegToRad(float deg)
  513. {
  514.  return(deg*PI/180.0);
  515. }
  516.  
  517. float RadToDeg(float rad)
  518. {
  519.  return(rad*180.0/PI);
  520. }
  521.  
  522. void SetAxesAngles(float rx, float ry, float rz) {
  523.     RX = DegToRad(rx);
  524.     RY = DegToRad(ry);
  525.     RZ = DegToRad(rz);
  526.     COSRX = cos(RX);
  527.     SINRX = sin(RX);
  528.     COSRY = cos(RY);
  529.     SINRY = sin(RY);
  530.     COSRZ = cos(RZ);
  531.     SINRZ = sin(RZ);
  532. }
  533.  
  534.  
  535.  
  536. POINT3D World3DToWorld2D(POINT3D p)
  537. {
  538.   POINT3D ptemp;
  539.   ptemp = p;
  540.   if (RX) {
  541.     ptemp.x  = p.x;
  542.     ptemp.y  = COSRX*p.y - SINRX*p.z;
  543.     ptemp.z  = SINRX*p.y + COSRX*p.z;
  544.     p = ptemp;
  545.   }
  546.   if (RY) {
  547.     ptemp.x  = COSRY*p.x + SINRY*p.z;
  548.     ptemp.y  = p.y;
  549.     ptemp.z  = -SINRY*p.x + COSRY*p.z;
  550.     p = ptemp;
  551.   }
  552.   if (RZ) {
  553.     ptemp.x  = COSRZ*p.x - SINRZ*p.y;
  554.     ptemp.y  = SINRZ*p.x + COSRZ*p.y;
  555.     ptemp.z  = p.z;
  556.   }
  557.   if (fabs(ptemp.x) < TOL)  ptemp.x = 0.0;
  558.   if (fabs(ptemp.y) < TOL)  ptemp.y = 0.0;
  559.   if (fabs(ptemp.z) < TOL)  ptemp.z = 0.0;
  560.   return(ptemp);
  561. }
  562.  
  563. POINTint World2DToDevice(POINT3D p)
  564. {
  565.  
  566.  POINTint ptemp;
  567.  ptemp.x = (WXleft-p.x)*(DXmax-DXmin)/(WXleft-WXright) + DXmin + 0.5;
  568.  ptemp.y = (WYtop-p.y)*(DYmax-DYmin)/(WYtop-WYbottom) + DYmin + 0.5;
  569.  return(ptemp);
  570.  
  571. }
  572.  
  573. void drawpoint(POINT3D p1)
  574. {
  575.  /* draws a 3D point   */
  576.  POINTint p2;
  577.  p1.z = -p1.z;
  578.  p2 = World2DToDevice(World3DToWorld2D(p1));
  579.  rectangle(p2.x - 2, p2.y - 2, p2.x + 2, p2.y + 2);
  580. }
  581.  
  582. void drawline(POINT3D p1,POINT3D p2)
  583. {
  584.  /* draws a 3D line  */
  585.   POINTint p11,p22;
  586.   p1.z = -p1.z;
  587.   p2.z = -p2.z;
  588.   p11  = World2DToDevice(World3DToWorld2D(p1));
  589.   p22  = World2DToDevice(World3DToWorld2D(p2));
  590.   line(p11.x,p11.y,p22.x,p22.y);
  591. }
  592.  
  593. void drawaxis(void) {
  594.   POINT3D p1,p2;
  595.  
  596.   p1.x = p1.y = p1.z = 0;
  597.  
  598.   p2.x = 1; p2.y = 0; p2.z=0;
  599.   setcolor(RED);
  600.   drawline(p1,p2);
  601.  
  602.   p2.x = 0; p2.y = 1; p2.z=0;
  603.   setcolor(GREEN);
  604.   drawline(p1,p2);
  605.  
  606.   p2.x = 0; p2.y = 0; p2.z=1;
  607.   setcolor(BLUE);
  608.   drawline(p1,p2);
  609.  
  610.   setcolor(WHITE);
  611. }
  612.